/*
实验11-2 查找树判断
分数 25
作者 DS课程组
单位 浙江大学

对于二叉查找树，我们规定任一结点的左子树仅包含严格小于该结点的键值，而其右子树包含大于或等于该结点的键值。
如果我们交换每个节点的左子树和右子树，得到的树叫做镜像二叉查找树。

现在我们给出一个整数键值序列，请编写程序判断该序列是否为某棵二叉查找树或某镜像二叉查找树的前序遍历序列，
如果是，则输出对应二叉树的后序遍历序列。

输入格式:

输入的第一行包含一个正整数 n（≤1000），第二行包含 n
个整数，为给出的整数键值序列，数字间以空格分隔。

输出格式:

输出的第一行首先给出判断结果，如果输入的序列是某棵二叉查找树或某镜像二叉查找树的前序遍历序列，则输出YES，否侧输出NO。如果判断结果是YES，下一行输出对应二叉树的后序遍历序列。数字间以空格分隔，但行尾不能有多余的空格。

输入样例1:

7
8 6 5 7 10 8 11

输出样例1:

YES
5 7 6 8 11 10 8

输入样例2:

7
8 6 8 5 10 9 11

输出样例2:

NO
*/

/*
解题思路：

    前序遍历序列的性质：

        对于二叉查找树，前序遍历的第一个元素是根节点。

        接下来的元素可以分为两部分：一部分是左子树的元素（严格小于根节点），另一部分是右子树的元素（大于或等于根节点）。

        对于镜像二叉查找树，左子树的元素大于或等于根节点，右子树的元素严格小于根节点。

    递归构建树：

        我们可以通过递归的方式，根据前序遍历序列构建二叉查找树或其镜像树。

        在构建过程中，如果发现序列不符合二叉查找树或其镜像的性质，则说明该序列不是合法的前序遍历序列。
*/
#include <climits>
#include <iostream>
#include <vector>

using namespace std;

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

// 判断是否是二叉查找树或其镜像的前序遍历
bool isBSTPreorder(vector<int> &preorder, int start, int end, int minVal,
                   int maxVal, bool isMirror) {
    if (start > end)
        return true;
    int rootVal = preorder[start];
    if (rootVal < minVal || rootVal > maxVal)
        return false;

    int splitIndex = start + 1;
    if (isMirror) {
        // 镜像树：左子树 >= 根，右子树 < 根
        while (splitIndex <= end && preorder[splitIndex] >= rootVal)
            splitIndex++;
        // 递归检查左子树和右子树
        return isBSTPreorder(preorder, start + 1, splitIndex - 1, rootVal,
                             maxVal, isMirror) &&
               isBSTPreorder(preorder, splitIndex, end, minVal, rootVal,
                             isMirror);
    } else {
        // 普通二叉查找树：左子树 < 根，右子树 >= 根
        while (splitIndex <= end && preorder[splitIndex] < rootVal)
            splitIndex++;
        // 递归检查左子树和右子树
        return isBSTPreorder(preorder, start + 1, splitIndex - 1, minVal,
                             rootVal, isMirror) &&
               isBSTPreorder(preorder, splitIndex, end, rootVal, maxVal,
                             isMirror);
    }
}

// 构建二叉查找树或其镜像树
TreeNode *buildTree(vector<int> &preorder, int start, int end, bool isMirror) {
    if (start > end)
        return nullptr;
    TreeNode *root = new TreeNode(preorder[start]);
    int splitIndex = start + 1;
    if (isMirror) {
        // 镜像树：左子树 >= 根，右子树 < 根
        while (splitIndex <= end && preorder[splitIndex] >= root->val)
            splitIndex++;
        root->left = buildTree(preorder, start + 1, splitIndex - 1, isMirror);
        root->right = buildTree(preorder, splitIndex, end, isMirror);
    } else {
        // 普通二叉查找树：左子树 < 根，右子树 >= 根
        while (splitIndex <= end && preorder[splitIndex] < root->val)
            splitIndex++;
        root->left = buildTree(preorder, start + 1, splitIndex - 1, isMirror);
        root->right = buildTree(preorder, splitIndex, end, isMirror);
    }

    return root;
}

// 后序遍历
void postorder(TreeNode *root, vector<int> &result) {
    if (!root)
        return;
    postorder(root->left, result);
    postorder(root->right, result);
    result.push_back(root->val);
}

int main() {
    int n;
    cin >> n;
    vector<int> preorder(n);
    for (int i = 0; i < n; ++i) {
        cin >> preorder[i];
    }

    // 判断是否是二叉查找树或其镜像的前序遍历
    bool isBST = isBSTPreorder(preorder, 0, n - 1, INT_MIN, INT_MAX, false);
    bool isMirrorBST =
        isBSTPreorder(preorder, 0, n - 1, INT_MIN, INT_MAX, true);

    if (!isBST && !isMirrorBST) {
        cout << "NO" << endl;
        return 0;
    }

    // 如果是，则构建树并输出后序遍历
    cout << "YES" << endl;
    TreeNode *root = buildTree(preorder, 0, n - 1, isMirrorBST);
    vector<int> postorderResult;
    postorder(root, postorderResult);

    // 输出后序遍历结果，确保行尾没有多余空格
    for (int i = 0; i < postorderResult.size(); ++i) {
        if (i > 0)
            cout << " ";
        cout << postorderResult[i];
    }
    cout << endl;

    return 0;
}
